/***********************************************************************************
 * 文件名： umi_static.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		通用存储器接口组件 Universal memory interface(UMI)。提供通用的存储器访问接口：
 *  Umi_Write、Umi_Read.  目前比较适用于操作MCU片上FLASH、小容量串行FLASH。
 * 修改记录：
 * 	2021/11/16: 初版。 刘言。 
***********************************************************************************/
#include "umi_static.h"
#include "polsys.h"



static void SafeWritePage(const u8 *buff, umi_addr_t addr, umi_size_t length);


bool Umi_Write(umi_addr_t addr, const u8 *buff, umi_size_t length)
{
    u16 addrDiff;
	
	if(length == 0) return true;    
#if (_UMI_ADDR_TYPE == 0)
	if(length + addr - _UMI_ADDR_BASE > _UMI_SIZE) return false;    // 错误
#else
    if(length + addr > _UMI_SIZE) return false;    // 错误
    addr += _UMI_ADDR_BASE;
#endif
    addrDiff = _UMI_PAGE_SIZE - (addr % _UMI_PAGE_SIZE);  // 本页剩余空间
    if(addrDiff < length)    // 剩余空间装不下所有的数据（超出了一页）,写本页剩余空间
    {
        SafeWritePage(buff, addr, addrDiff);
        buff += addrDiff;
        addr += addrDiff;
        length -= addrDiff;
    }
    while(length > _UMI_PAGE_SIZE) //剩余长度大于页大小
    {
        _Umi_MemoryWritePage(addr, buff);  //写入一整页
        buff += _UMI_PAGE_SIZE;
        addr += _UMI_PAGE_SIZE;
        length -= _UMI_PAGE_SIZE;
    }
    if(length > 0) SafeWritePage(buff, addr, length);   // 写入最后不足一页长度的数据
    return true;
}

bool Umi_Read(umi_addr_t addr, u8 *buff, umi_size_t length)
{
    if(length == 0) return true;    
#if (_UMI_ADDR_TYPE == 0)
	if(length + addr - _UMI_ADDR_BASE > _UMI_SIZE) return false;    // 错误
#else
    if(length + addr > _UMI_SIZE) return false;    // 错误
    addr += _UMI_ADDR_BASE;
#endif
    _Umi_MemoryRead(addr, buff, length);
    return true;
}


/****************************************************************************
* 功    能: 使用 读改写 方法，安全的（不破坏数据）向1个页写入部分数据
* 入口参数: buff:要写入的数据 addr:写入地址, length:写入数据长度（字节数）
* 出口参数: 
* 说    明: 需保证写入数据在同一页内
* 调用方法: 
****************************************************************************/
static void SafeWritePage(const u8 *buff, umi_addr_t addr, umi_size_t length)
{
	umi_addr_t addrPage;  // 页首地址
    u16 addrDiff;       // 页内偏移地址
	u16 i;
#if _UMI_USE_MRM == 0
	ALIGN(4) u8 page_buff[_UMI_PAGE_SIZE];     // 写入缓存
#else
    u8 *page_buff = _Umi_Alloc(_UMI_PAGE_SIZE);
    while(page_buff == NULL);
#endif
	
	addrPage = (addr/_UMI_PAGE_SIZE)*_UMI_PAGE_SIZE;
	addrDiff = addr % _UMI_PAGE_SIZE;
	// 读取整页原数据
	for(i = 0; i < _UMI_PAGE_SIZE; i++)
	{
        page_buff[i] = *((u8 *)addrPage + i);
	}
	// 修改需要写的数据
	for(i = 0; i < length; i++)
	{
        page_buff[addrDiff + i] = buff[i];
	}
    //写入新的一整页数据
    _Umi_MemoryWritePage(addrPage, page_buff);

#if _UMI_USE_MRM == 1
    _Umi_Free(page_buff);
#endif
}








